/*
 * File:    Compiler.java
 * Created: 07-Nov-2004
 * Version: $Id: //depot/bitgate/bsse/src/bitgate/util/compiler/Compiler.java#1 $
 *
 * COPYRIGHT (C) 2004, 2005, Bitgate Software, LLC.  All Rights Reserved.
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.compiler;

import static com.bitgate.util.debug.Debug.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * This class is used to dynamically compile Java code on the fly, without having to create a new instance of the JVM through
 * system resources.  This code is similar to what JIT compiling does, and similar to the mechanism that is used by JSP.
 * JSP is slightly less efficient, as it calls the &quot;javac&quot; to compile its code rather than using the internally
 * available java compiler.
 *
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @version $Id: //depot/bitgate/bsse/src/bitgate/util/compiler/Compiler.java#1 $
 */
public class Compiler
{
    private String filename;
    private boolean deleteOnExit;

    /**
     * Creates a new compiler object.
     *
     * @param filename The filename to compile (or create to compile.)
     */
    public Compiler(String filename)
    {
		this.filename = filename;
		this.deleteOnExit = true;
    }

    /**
     * Creates a new compiler object, without an assigned filename.  When no filename is specified, it is implied that the
     * filename will be created on the fly.
     */
    public Compiler()
    {
		this.filename = null;
		this.deleteOnExit = true;
    }

    /**
     * Returns whether or not the compiler source file is to be deleted after compile.
     *
     * @return <code>true</code> if delete on exit, <code>false</code> otherwise.
     */
    public boolean isDeleteOnExit()
    {
		return this.deleteOnExit;
    }

    /**
     * Sets whether or not to delete the compiler source file on exit.
     *
     * @param deleteOnExit The flag to set.
     */
    public void setDeleteOnExit(boolean deleteOnExit)
    {
    	this.deleteOnExit = deleteOnExit;
    }

    /**
     * Sets the body of the file that will be compiled.  If no filename was specified during the creation of the Compiler
     * object, the filename is automatically created.  The problem with this, however, is when a file is created on the
     * fly, the current working directory (read, the directory from which the program is running) is used to build from.
     *
     * @param buf The buffer to compile.
     * @throws IOException on any I/O related issues.
     * @throws FileNotFoundException on any files that could not be created or modified.
     */
    public void setCompileData(StringBuffer buf) throws IOException, FileNotFoundException
    {
		File file;
	
		if (this.filename == null) {
		    file = File.createTempFile("jav", ".java", new File(System.getProperty("user.dir")));
	
		    this.filename = file.getName();
		} else {
		    file = new File(this.filename);
		}
	
		if (this.deleteOnExit) {
		    file.deleteOnExit();
		}
	
		PrintWriter out = new PrintWriter(new FileOutputStream(file));
	
		out.print(buf.toString());
		out.flush();
		out.close();
	
		if (isDebugEnabled()) {
			debug("Set compiler filename to '" + file + "'");
		}
    }

    /**
     * Retrieves the current filename.
     *
     * @return <code>String</code> containing the filename.
     */
    public String getFilename()
    {
    	return this.filename;
    }

    /**
     * Compiles the specified filename.
     *
     * @throws CompilerException on any errors.
     */
    public void compile() throws CompilerException
    {
//		String args[] = { this.filename };
//		int result = 0;
//		
//		try {
//		    result = com.sun.tools.javac.Main.compile(args);
//		} catch(NoClassDefFoundError e) {
//		    throw new CompilerException("Unable to compile: Compiler not in classpath, or unavailable.");
//		}
//	
//		switch(result) {
//		    case 0:	return;
//		    case 1:	throw new CompilerException("Internal compiler error.");
//		    case 2:	throw new CompilerException("Compiler command error.");
//		    case 3:	throw new CompilerException("System error during compile.");
//		    case 4:	throw new CompilerException("Abnormal system error during compile.");
//		    default:	throw new CompilerException("Compile failed: Unknown error result '" + result + "'");
//		}
    }
}
